package com.jsh.erp.utils;



import com.jsh.erp.controller.MaterialController;
import com.jsh.erp.datasource.entities.BarCodeScaleGoods;
import org.apache.http.util.TextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * @ClassName: SocketUtils
 * @Description:
 *         try
 *             {
 *                 int port = 4001;
 *                 IPAddress ip = IPAddress.Parse(textBox1.Text.Trim());
 *                 IPEndPoint ipe = new IPEndPoint(ip, port);
 *                 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 *                 socket.Connect(ipe);
 *                 var name = "毛豆";//商品名称
 *                 var barCodd = "123456";//商品条码
 *                 var shelfLife = 2;//商品有效期
 *                 var nameConvert = GetChineseWord(name);
 *                 var plu = "1";
 *                 var price = 10.1;//单价分
 *                 StringBuilder qwm = new StringBuilder();
 *                 foreach (var c in nameConvert)
 *                 {
 *                     qwm.Append(getCode(c.ToString()));
 *                 }
 *                 //$"!0V{4位PLU}A{7位商品编码}{6位数价格（单位分）}{模式（0：称重，1：计件，2：定重）}000000{3位有效期}{2位店号（01-99）}000000000000000{2位皮重（00-15）}0000000000000000000000000000000B{商品名称区位码}CDE" + "\r\n";
 *                 string sendStr = $"!0V{plu.PadLeft(4, '0')}A{barCodd.PadLeft(7, '0')}{(price * 100).ToString().PadLeft(6, '0')}0000000{shelfLife.ToString().PadLeft(3, '0')}01000000000000000000000000000000000000000000000000B{qwm}CDE" + "\r\n";
 *                 byte[] bs = Encoding.ASCII.GetBytes(sendStr);
 *                 socket.Send(bs, bs.Length, 0);
 *                 string recvStr = "";
 *                 byte[] recvBytes = new byte[1024];
 *                 int bytes;
 *                 bytes = socket.Receive(recvBytes, recvBytes.Length, 0);
 *                 recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
 *                 socket.Close();
 *
 *                 MessageBox.Show("下发成功");
 *             }
 *             catch (Exception ex)
 *             {
 *
 *                 MessageBox.Show("异常：" + ex.Message);
 *             }
 * @Author: 有时有晌
 * @Date: 2021/11/15 21:54
 */
public class SocketUtils {
    private Logger logger = LoggerFactory.getLogger(MaterialController.class);
    private Socket socket;
    private BufferedReader bufferedReader;
    private SocketUtils socketUtils;
    public SocketUtils getSocketUtils(){
        if (socketUtils==null){
            socketUtils = new SocketUtils();
        }
        return socketUtils;
    }

    /**
     * socket连接大华条码秤 端口固定是4001(大华秤自己的端口，不要修改)修改后无法连接
     * @param ip
     */
    public boolean connect(String ip){
        try {
            socket = new Socket();
            InetSocketAddress socketAddress = new InetSocketAddress(TextUtils.isEmpty(ip)?"192.168.108.200":ip, 4001);
            socket.connect(socketAddress, 10 * 1000);
            socket.setSoTimeout(5 * 1000);
            if (socket.isConnected()) {
                // 向 socket 服务器写入数据
//                byte[] bytes = {0x21, 0x30, 0x49, 0x41, 0x0d, 0x0a, 0x03};
//                socket.getOutputStream().write(bytes);
//                socket.getOutputStream();
                //上边38  39行 是每次写入前都执行清理
                // 接收 socket 服务器返回的数据
                InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
                bufferedReader = new BufferedReader(ipr);
//                try {
//                    String str = bufferedReader.readLine();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
            }
            return socket.isConnected();
        } catch (IOException error) {
            error.printStackTrace();
            System.out.println("==-->socket连接异常");
        }
        return false;
    }

    /**
     * 发送指令
     * @param bytes
     * @return
     */
    private String sendCommand(byte[] bytes) {
        byte[] suffix = {0x0d, 0x0a, 0x03};
        try {
            if (socket != null && socket.isConnected() && socket.getOutputStream() != null) {

                byte[] command = Utils.byteMerger(bytes, suffix);
                socket.getOutputStream().write(command);
                logger.info("TAG==-->指令发送成功");
                return "SEND_SUCCESS";

            } else {
                return "NOT_CONNECT";
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "SEND_FAIL";
        }
    }



    /**
     * 清除大华秤内部商品
     * @return
     */
    public boolean clearData() {
        if (socket != null && socket.isConnected()) {
            byte[] bytes = {0x21, 0x30, 0x49, 0x41};
            sendCommand(bytes);
            byte[] bytes2 = {0x21, 0x30, 0x48, 0x41};
            sendCommand(bytes2);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 修改条码打印后缀为价格
     * @return
     */
    public boolean changePrice() {
        if (socket != null && socket.isConnected()) {
            String priceType = modelPrice();
            byte[] bytes = priceType.getBytes();
            String result = sendCommand(bytes);
//            logger.info("TAG==-->发送改为价格指令"+result);
            if (result.equals("SEND_SUCCESS")) {
                try {
                    InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
                    bufferedReader = new BufferedReader(ipr);
                    String str = bufferedReader.readLine();
                    if (str.length() > 0) {
//                        logger.info("TAG==-->发送改为价格指令成功");
                        return true;
                    } else {
//                        logger.info("TAG==-->发送改为价格指令失败");
                        return false;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
//                    logger.info("TAG==-->发送改为价格指令失败发生异常"+e.getMessage()+" "+e.getCause());
                    return false;
                }
            } else {
//                logger.info("TAG==-->发送改为价格指令 ！SEND_SUCCESS");
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 修改条码打印后缀为重量
     * @return
     */
    public boolean changeWeight() {
        if (socket != null && socket.isConnected()) {
            String modelWeight = modelWeight();
            byte[] bytes = modelWeight.getBytes();
            String result = sendCommand(bytes);
//            logger.info("TAG==-->发送改为重量指令"+result);
            if (result.equals("SEND_SUCCESS")) {
                try {
                    InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
                    bufferedReader = new BufferedReader(ipr);
                    String str = bufferedReader.readLine();
                    if (str.length() > 0) {
//                        logger.info("TAG==-->发送改为重量指令成功");
                        return true;
                    } else {
//                        logger.info("TAG==-->发送改为重量指令失败");
                        return false;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
//                    logger.info("TAG==-->发送改为重量指令失败发生异常"+e.getMessage()+" "+e.getCause());
                    return false;
                }
            } else {
//                logger.info("TAG==-->发送改为重量指令失败 ！SEND_SUCCESS");
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 更新条码后缀为价格值
     * !0O[协议头]
     * 01[秤号]
     * 05[打印浓度]
     * 00[是否打折]
     * 01[抹零允许]
     * 02[条码格式]
     * 01[条码类型]
     * 01[分位圆整]
     * 01[日期格式]
     * 00[净重单位]
     * 00[单价单位]
     * 01[钱箱驱动开关]
     * 00[量程选折]
     * 01[打印是否清零]
     * 00[连续纸条码设置]
     * 00[金额厘位设置]
     * 00[表头1字体]
     * 00[表头2字体]
     * 00[表头3字体]
     * 00[表头4字体]
     * 00[表尾1字体]
     * 00[表尾2字体]
     * 00[表尾3字体]
     * 00[表尾4字体]
     * 01[正文字体]
     * @return
     */
    private static String modelPrice() {
        String modePrice = "!0O010503000501000100010100010001000000000000000001";
        return modePrice;
    }
    /**
     * 更新条码后缀为重量值
     * !0O[协议头]
     * 01[秤号]
     * 05[打印浓度]
     * 00[是否打折]
     * 01[抹零允许]
     * 02[条码格式]
     * 01[条码类型]
     * 01[分位圆整]
     * 01[日期格式]
     * 00[净重单位]
     * 00[单价单位]
     * 01[钱箱驱动开关]
     * 00[量程选折]
     * 01[打印是否清零]
     * 00[连续纸条码设置]
     * 00[金额厘位设置]
     * 00[表头1字体]
     * 00[表头2字体]
     * 00[表头3字体]
     * 00[表头4字体]
     * 00[表尾1字体]
     * 00[表尾2字体]
     * 00[表尾3字体]
     * 00[表尾4字体]
     * 01[正文字体]
     * @return
     */
    private String modelWeight() {
//        String modelWeight = "!0O010503010202000100010100010001000000000000000001";//这个能正常打印重量 但是barCode不对 -- 留作备份
        String modelWeight = "!0O010503010502000100010100010001000000000000000001";//这个能正常打印重量 barCode打印头正确 保持与price条码格式都为05
        return modelWeight;
    }

    /**
     * 设置写入商品
     * @param goods
     * @return
     */
    public boolean setGoods(BarCodeScaleGoods goods) {
        if (!socket.isConnected()){
//            logger.info("TAG==-->socket没有连接");
            return false;
        }
        String plu = goods.pluCode;
        String code = goods.code;
        String price = String.valueOf(new Double(goods.price * 100).intValue());
        String goodsName = Utils.StringToAreaByteCode(goods.goodsName);
        String unit = goods.unit;
        String barHeader = goods.barCodeHeader;
        //需满足大华秤内部自身长度，不够追加
        while (plu.length() < 4) {
            plu = '0' + plu;
        }
        while (price.length() < 6) {
            price = '0' + price;
        }
        // %s 为占位符 依次用后边 plu   code  price  unit barHeader goodsName 替换 具体长度请参考大华秤自己demo 内部有固定长度要求
        // 如 plu 固定长度为4位，长度不够自行拼接0
//        String goodsInfo = String.format("!0V%sA%s%s%s000000999%s010000000000000000000000000000000000000000000000B%sCDE", plu, code, price, unit,barHeader,goodsName);//这个条形码前缀以动态输入
        String goodsInfo = String.format("!0V%sA%s%s%s00000099901010000000000000000000000000000000000000000000000B%sCDE", plu, code, price, unit, goodsName);//这个条形码按大华机器走
        logger.info("TAG==-->大华电子秤 最终 str：= "+goodsInfo);
        byte[] bytes = goodsInfo.getBytes();
        String result = sendCommand(bytes);
        //根据sendCommand返回结果判断
        if (result.equals("SEND_SUCCESS")) {
            try {
                InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
                bufferedReader = new BufferedReader(ipr);
                String str = bufferedReader.readLine();
                if (str.length() > 0) {
                    logger.info("TAG==-->商品下发成功");
                    return true;
                } else {
                    logger.info("TAG==-->商品下发失败");
                    return false;
                }
            } catch (IOException e) {
                e.printStackTrace();
                logger.info("TAG==-->商品下发失败发生异常"+e.getMessage()+" "+e.getCause());
                return false;
            }
        } else {
            logger.info("TAG==-->商品下发失败 ！SEND_SUCCESS");
            return false;
        }
    }

    /**
     * 设置商品参数
     * @param str
     * @return
     */
    public boolean setGoods(String str) {
        if (!socket.isConnected()){
            logger.info("TAG==-->socket没有连接");
            return false;
        }
//        name = Utils.StringToAreaByteCode(name);
//        String goodsInfo = String.format(str,name);//这个条形码按大华机器走
//        logger.info("TAG==-->大华电子秤 最终 str：= "+goodsInfo);
//        String goodsInfo = String.format(str,name);//这个条形码按大华机器走
        logger.info("TAG==-->大华电子秤 最终 str：= "+str);
        byte[] bytes = str.getBytes();
        String result = sendCommand(bytes);
        //根据sendCommand返回结果判断
        if (result.equals("SEND_SUCCESS")) {
            try {
                InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
                bufferedReader = new BufferedReader(ipr);
                String readLine = bufferedReader.readLine();
                if (readLine.length() > 0) {
                    logger.info("TAG==-->商品下发成功");
                    return true;
                } else {
                    logger.info("TAG==-->商品下发失败");
                    return false;
                }
            } catch (IOException e) {
                e.printStackTrace();
                logger.info("TAG==-->商品下发失败发生异常"+e.getMessage()+" "+e.getCause());
                return false;
            }
        } else {
            logger.info("TAG==-->商品下发失败 ！SEND_SUCCESS");
            return false;
        }
    }

    /**
     * 执行完成关闭socket
     */
    public void closeConnect(){
        try{
            if (socket!=null||socket.isConnected()){
//                logger.info("TAG==-->socket关闭连接");
                try {
                    if(socket.getOutputStream()!=null){
                        socket.getOutputStream().close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (socket.getInputStream()!=null){
                        socket.getInputStream().close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if(socket!=null){
                        socket.close();
                        socket=null;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    bufferedReader = null;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        BarCodeScaleGoods barCodeScaleGoods = new BarCodeScaleGoods();
        barCodeScaleGoods.setPluCode("109");
//        barCodeScaleGoods.setBarCodeHeader("51556851513");
        barCodeScaleGoods.setCode("1002");
        barCodeScaleGoods.setPrice(12.16);
        barCodeScaleGoods.setGoodsName("黑麦面包");
        barCodeScaleGoods.setUnit("1");
        SocketUtils socketUtils = new SocketUtils();
        socketUtils.connect("192.168.8.223");
        socketUtils.setGoods(barCodeScaleGoods);
//        socketUtils.closeConnect();
    }
}
